//------------------------------------------------------------------------------
//
//   author: 小兵（aosnow@yeah.net）
//   create: 2012-5-31 上午10:29:36
//    class: LoadAgent - 加载器任务代理
//
//------------------------------------------------------------------------------

package starfire.rpc.loader
{
	import flash.errors.IllegalOperationError;
	
	import starfire.handlers.Handler;
	import starfire.rpc.loader.elements.*;

	/**
	 * 加载器任务代理，用于加载单任务或者队列任务
	 * @author AoSnow
	 */
	public class LoadAgent
	{

		public function LoadAgent()
		{
		}

		//--------------------------------------------------------------------------
		//
		//   单条任务加载
		//
		//--------------------------------------------------------------------------

		/**
		 * 根据 message 的描述信息加载指定的资源（单个加载，即时启动加载，要进行队列加载请使用 loadList）
		 * @param message				- 描述信息
		 * @param complete				- 完成时的回调函数，参数为 取得的相应数据
		 * @param process				- 加载进度时的回调函数，参数为 flash.events.ProgressEvent
		 * 
		 * <p>
		 * 成功返回结果时，参数类型如下：
		 * <ul>
		 * <li>MediaType.VIDEO	- 暂不支持视频内容加载</li>
		 * <li>MediaType.AUDIO	- 返回结果为 Sound，回调方法参数示例：<br/><code>function(sound:Sound)</code></li>
		 * <li>MediaType.IMAGE	- 返回结果为原始 LoadMessage，其 result 将存储所加载的 BitmapData 返回，
		 * 回调方法参数示例：<br/><code>function(message:LoadMessage)</code></li>
		 * <li>MediaType.SWF	- 返回结果为包含 SWF 内容的LoaderInfo，回调方法参数示例：<br/><code>function(content:LoaderInfo)</code></li>
		 * <li>MediaType.BINARY	- 返回结果为 ByteArray，回调方法参数示例：<br/><code>function(byteArray:ByteArray)</code></li>
		 * <li>MediaType.TEXT	- 返回结果为 String，回调方法参数示例：<br/><code>function(text:String)</code></li>
		 * <li>MediaType.XML	- 返回结果为 XML，回调方法参数示例：<br/><code>function(xml:XML)</code></li>
		 * </ul>
		 * </p>
		 *
		 * @see starfire.rpc.loader.LoadMessage
		 * @see flash.events.ProgressEvent
		 */
		public function load( message:LoadMessage, complete:Function = null, process:Function = null ):void
		{
			var loader:LoaderBase = loadSingle( message, complete, process );

			if( loader )
				loader.load();
		}

		public function loadSingle( message:LoadMessage, complete:Function = null, process:Function = null ):LoaderBase
		{
			if( message == null || message && ( message.url == "" || message.url == null ))
				throw new IllegalOperationError( "ERROR: 未设置正确的加载描述信息！" );

			// 若资源已经加载过，则直接取回不再重复加载
			if( MediaCache.hasResource( message.mediaType, message.name ))
			{
				if( complete is Function )
				{
					complete( MediaCache.getDataByMessage( message ));
				}

				return null;
			}

			// 根据描述信息创建对应的加载器进行加载
			var loader:LoaderBase;

			switch( message.mediaType )
			{
				case MediaType.IMAGE:
					loader = new ImageLoader( message );
					break;
				case MediaType.SWF:
					loader = new SWFLoader( message );
					break;
				case MediaType.BINARY:
					loader = new BinaryLoader( message );
					break;
				case MediaType.VIDEO:
					loader = new VideoLoader( message );
					break;
				case MediaType.AUDIO:
					loader = new AudioLoader( message );
					break;
				case MediaType.TEXT:
					loader = new TextLoader( message );
					break;
				case MediaType.XML:
					loader = new XMLLoader( message );
					break;
				default:
					throw new IllegalOperationError( "ERROR: 非法的资源类型！" );
			}

			loader.complete = complete;
			loader.progress = process;

			return loader;
		}

		//--------------------------------------------------------------------------
		//
		//   队列任务加载
		//
		//--------------------------------------------------------------------------

		private var _messages:Vector.<LoadMessage>;
		private var _complete:Handler;
		private var _process:Handler;
		private var _singleProcess:Function;

		private var _total:uint;
		private var _realComplete:uint;
		private var _numComplete:uint;

		/**
		 * 根据 messages 队列的描述信息加载指定的资源（队列加载，初始完队列设置后自动开始启动加载）
		 * <p>若以下 Handler 类型的回调方法增加了自定义参数，将合并到以下所描述的标准参数之前，同时返回</p>
		 * @param messages				- 描述信息队列
		 * @param complete				- 完成时的回调函数，参数为 [ 实际加载的数量, 完成数量, 总数量 ]（若任务中包含已经加载过的任务，则会被忽略，这时实际加载数量就会减 1）
		 * @param process				- 总体加载进度时的回调函数，参数为 [ 完成数量, 总数量 ]
		 * @param singleProcess			- 单个加载任务加载进度时的回调函数，参数为正在处理的任务的 ProgressEvent
		 *
		 * <p>若要取得加载数据，请从 MediaCache 类的缓存中获取，这需要用到加载描述信息中所设置的名称标识。</p>
		 */
		public function loadList( messages:Vector.<LoadMessage>, complete:Handler = null, process:Handler = null, singleProcess:Function = null ):void
		{
			if( messages && messages.length > 0 )
			{
				_messages = messages;
				_complete = complete;
				_process = process;
				_singleProcess = singleProcess;

				_total = messages.length;
				_realComplete = _total;
				_numComplete = 0;

				// 启动加载队列
				executeLoadList( _messages );
			}
		}

		protected function executeLoadList( messages:Vector.<LoadMessage> ):void
		{
			var msg:LoadMessage = messages.shift();
			var loader:LoaderBase = loadSingle( msg, null, _singleProcess );

			if( loader )
			{
				loader.complete = loadListCompleteHandler;
				loader.error = loadError;
				loader.load();
			}
			else
			{
				_realComplete--; // 真实加载数量减 1

				loadListCompleteHandler( null );
			}
		}
		
		protected function loadError( text:String ):void
		{
			// 加载出错，直接跳过当前加载任务
			loadListCompleteHandler( null );
		}

		protected function loadListCompleteHandler( data:Object ):void
		{
			_numComplete++;

			// 任务进度
			if( _process is Handler )
			{
				_process.executeWith([ _numComplete, _total ]);
			}

			// 检测任务是否全部完成
			if( _messages.length <= 0 )
			{
				if( _complete is Handler )
				{
					_complete.executeWith([ _realComplete, _numComplete, _total ]);
				}
			}
			else
			{
				executeLoadList( _messages );
			}
		}
	}
}
